1.1.1 概述
画图需要两个工具:纸和笔。在 Android 中,Paint 类就是画笔,而 Canvas 类就是纸,在这里叫作画布。
凡是跟画笔设置相关的,比如画笔大小、粗细、画笔颜色、透明度、字体的样式等,都在 Paint 类里设置;同样,凡是要画出成品的东西,比如圆形、矩形、文字等,都调用 Canvas 类里的函数生成。
示例:
|
|
直接在主布局中使用自定义控件
在 onDraw() 函数中不能创建变量。因为当需要重绘时就会调用 onDraw() 函数,这样会导致变量一直被重复创建,会引起频繁的程序 GC (回收内存),进而引起程序卡顿。一般在构造函数中创建变量。
1.1.2 画笔的基本设置
1. setAntiAlias()
|
|
表示是否打开抗锯齿功能。抗锯齿是依赖算法的,一般在绘制不规则的图形时使用,比如圆形、文字等。在绘制棱角分明的图像时,比如一个矩形、一张位图,是不需要打开抗锯齿功能的。
示例:
|
|
2. setColor()
|
|
设置画笔颜色。一个颜色值是由红、绿、蓝三色合成出来的,所以,参数 color 只能取 8 位的 0xAARRGGBB 样式颜色值。其中:
- A 代表透明度(Alpha),取值范围是 0~255(对应十六进制的 0x00~0xFF),取值越小,透明度越高,图像也就越透明。当取 0 时,图像完全不可见。
- R 代表红色值(Red),取值范围是 0~255(对应十六进制的 0x00~0xFF),取值越小,红色越少。当取 0 时,表示红色完全不可见;当取 255 时,红色完全显示。
- G 代表绿色值(Green),取值范围是 0~255(对应十六进制的 0x00~0xFF),取值越小,绿色越少。当取 0 时,表示绿色完全不可见;当取 255 时,绿色完全显示。
- B 代表蓝色值(Blue),取值范围是 0~255(对应十六进制的 0x00~0xFF),取值越小,蓝色越少。当取 0 时,表示蓝色完全不可见;当取 255 时,蓝色完全显示。
示例:
|
|
3. setStyle()
|
|
设置填充样式,对于文字和几何图形都有效。style 的取值如下:
- Paint.Style.FILL:仅填充内部。
- Paint.Style.FILL_AND_STROKE:填充内部和描边。
- Paint.Style.STROKE:仅描边。
示例:
|
|
4. setStrokeWidth()
|
|
设置描边宽度值,单位是 px。当画笔的 Style 样式是 STROKE、FILL_AND_STROKE 时有效。当 Style 不起作用时,用于设置画笔宽度。
1.1.3 Canvas使用基础
1. 画布背景设置
有三种方法可以实现画布背景设置:
drawColor() 函数中参数 color 的取值必须是 8 位的 0xAARRGGBB 样式颜色值。
drawARGB() 函数允许分别传入 A、R、G、B 分量,每个颜色值的取值范围都是 0~255(对应十六进制的 0x00~0xFF),内部会通过这些颜色分量构造出对应的颜色值。 drawRGB() 函数只允许传入 R、G、B 分量,透明度 Alpha 的值取 255。
示例:
|
|
2. 画直线
|
|
参数:
- startX:起始点 X 坐标。
- startY:起始点 Y 坐标。
- stopX:终点 X 坐标。
- stopY:终点 Y 坐标。
示例:
|
|
从效果图中可以明显看出,直线的粗细与画笔 Style 是没有关系的。当设置不同的 StrokeWidth 时,效果如下图所示。
|
|
可见,直线的粗细是与 paint.setStrokeWidth 有直接关系的。所以,一般而言,paint.setStrokeWidth 在 Style 起作用时,用于设置描边宽度;在 Style 不起作用时,用于设置画笔宽度。
3. 多条直线
|
|
参数:
pts:点的集合。从下面的代码中可以看到,这里不是形成连接线,而是每两个点形成一条直线,pts 的组织方式 {x1,y1,x2,y2,x3,y3,…}。
示例:
|
|
上面有 4 个点,分别是(10,10)、(100,100)、(200,200)和(400,400),两两连成一条直线。
另一个构造函数:
相比上面的构造函数,这里多了两个参数。
- int offset:集合中跳过的数值个数。注意不是点的个数!一个点有两个数值。
- int count:参与绘制的数值个数,指 pts 数组中数值的个数,而不是点的个数,因为一个点有两个数值。
|
|
表示从 pts 数组中索引为 2 的数字开始绘图,有 4 个数值参与绘图,也就是点(100,100) 和(200,200),所以效果图就是这两个点的连线。
4. 点
|
|
示例:
|
|
在(100,100)位置画一个点。同样,点的大小只与 paint.setStrokeWidth(width) 有关,而与 paint.setStyle 无关。
5. 多个点
|
|
这几个参数的含义与多条直线中的参数含义相同。
- float[] pts:点的合集,与上面的直线一致,样式为{x1,y1,x2,y2,x3,y3,…}。
- int offset:集合中跳过的数值个数。注意不是点的个数!一个点有两个数值。
- int count:参与绘制的数值个数,指 pts 数组中数值的个数,而不是点的个数。
示例:
|
|
同样是上面的 4 个点:(10,10)、(100,100)、(200,200)和(400,400),在 drawPoints()函数里跳过前两个数值,即第一个点的横、纵坐标,画出后面 4 个数值代表的点,即第二、三个点,第四个点没画。
6. RectF & Rect
这两个类都是矩形工具类,根据 4 个点构造出一个矩形结构。RectF 与 Rect 中的方法、 成员变量完全一样,唯一不同的是:RectF 是用来保存 float 类型数值的矩形结构的;而 Rect 是用来保存 int 类型数值的矩形结构的。
一般而言,要构造一个矩形结构,可以通过以下两种方法来实现。
7. 矩形
|
|
第一个函数是直接传入矩形的 4 个点来绘制矩形的;第二、三个函数是根据传入 RectF 或者 Rect 的矩形变量来指定所绘制的矩形的。
示例:
|
|
8. 圆角矩形
|
|
参数:
- RectF rect:要绘制的矩形。
- float rx:生成圆角的椭圆的 X 轴半径。
- float ry:生成圆角的椭圆的 Y 轴半径。
示例:
|
|
9. 圆形
|
|
参数:
- float cx:圆心点的 X 轴坐标。
- float cy:圆心点的 Y 轴坐标。
- float radius:圆的半径。
10. 椭圆
|
|
参数:
RectF oval:用来生成椭圆的矩形。
椭圆是根据矩形生成的,以矩形的长为椭圆的 X 轴,以矩形的宽为椭圆的 Y 轴。
示例:
|
|
11. 弧
|
|
参数:
- RectF oval:生成椭圆的矩形。
- float startAngle:弧开始的角度,以 X 轴正方向为 0°。
- float sweepAngle:弧持续的角度。
- boolean useCenter:是否有弧的两边。为 true 时,表示带有两边;为 false 时,只有一条弧。
示例:
|
|
上述代码中,仅将 paint 的样式设置为 FILL 。效果图如下:
当画笔设为填充模式时,填充区域只限于圆弧的起始点和终点所形成的区域。当带有两边时,会将两边及圆弧内部全部填充;如果没有两边,则只填充圆弧部分。
1.1.4 Rect与RectF
1.是否包含点、矩形
1)判断是否包含某个点
该函数用于判断某个点是否在当前矩形中。如果在,则返回 true;如果不在,则返回 false。 参数(x,y)就是当前要判断的点的坐标。
示例:绘制一个灰色矩形,当手指在这个矩形区域内时,矩形变为红色。
|
|
上述代码注意两点:
在 MotionEvent.ACTION_DOWN 中返回 true,因为当 MotionEvent. ACTION_DOWN 消息到来时,系统会判断返回值,当返回 true 时,表示当前控件已经在拦截 (消费)这个消息了,所以后续的 ACTION_MOVE、ACTION_UP 消息仍然继续传过来。如果返回 false(系统默认返回 false),就表示当前控件不需要这个消息,那么后续的 ACTION_MOVE、ACTION_UP 消息就不会再传到这个控件。
postInvalidate() 和 invalidate() 函数都是用来重绘控件的,区别是 invalidate() 函数一定要在主线程中执行,否则就会报错;而 postInvalidate() 函数则没有那么多讲究,它可以在任何线程中执行,而不必一定是主线程。因为在 postInvalidate() 函数中就是利用 handler 给主线程发送刷新界面的消息来实现的,所以它可以在任何线程中执行而不会出错。而正因为它是通过发送消息来实现的,所以它的界面刷新速度可能没有直接调用 invalidate() 函数那么快。确定当前线程是主线程的情况下,以 invalidate() 函数为主。否则调用调用 postInvalidate() 函数为好。因为 onTouchEvent() 函数本来就是在主线程中的,所以使用 invalidate() 函数更合适。
2)判断是否包含某个矩形
2.判断两个矩形是否相交
1)静态方法判断是否相交
这是 Rect 类的一个静态方法,用来判断参数中所传入的两个 Rect 矩形是否相交,如果相交则返回 true,否则返回 false。
2)成员方法判断是否相交
判断当前 Rect 对象与其他矩形是否相交。
使用方法:
3)判断相交并返回结果
这两个成员方法与 intersects()方法的区别是,不仅会返回是否相交的结果,而且会把相交部分的矩形赋给当前 Rect 对象。如果两个矩形不相交,则当前 Rect 对象的值不变。
3.合并
1)合并两个矩形
合并两个矩形的意思就是将两个矩形合并成一个矩形,即无论这两个矩形是否相交,取两个矩形最小左上角点作为结果矩形的左上角点,取两个矩形最大右下角点作为结果矩形的右下角点。如果要合并的两个矩形有一方为空,则将有值的一方作为最终结果。
示例:
|
|
2)合并矩形与某个点
先判断当前矩形与目标合并点的关系。如果不相交,则根据目标点(x,y)的位置,将目标点设置为当前矩形的左上角点或者右下角点。如果当前矩形是一个空矩形,则最后的结果矩形为([0,0],[x,y]),即结果矩形的左上角点为[0,0],右下角点为[x,y]。
1.1.5 Color
Color 是 Android 中与颜色处理有关的类。
1. 常量颜色
|
|
Color.XXX 来直接使用这些颜色,比如红色:Color.RED。
2. 构造颜色
|
|
argb() 函数的源码:
3. 提取颜色分量
|
|
通过上面的 4 个函数提取出对应的 A、R、G、B 颜色分量。